home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 28
/
Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso
/
Aminet
/
game
/
board
/
Crafty-15.19.lha
/
crafty-15.19
/
src
/
search.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-09-13
|
21KB
|
489 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "chess.h"
#include "data.h"
#include "epdglue.h"
/* last modified 06/05/98 */
/*
********************************************************************************
* *
* Search() is the recursive routine used to implement the alpha/beta *
* negamax search (similar to minimax but simpler to code.) Search() is *
* called whenever there is "depth" remaining so that all moves are subject *
* to searching, or when the side to move is in check, to make sure that this *
* side isn't mated. Search() recursively calls itself until depth is ex- *
* hausted, at which time it calls Quiesce() instead. *
* *
********************************************************************************
*/
int Search(TREE *tree, int alpha, int beta, int wtm, int depth,
int ply, int do_null) {
register int moves_searched=0;
register BITBOARD save_hash_key;
register int initial_alpha, value=0;
register int extensions, pieces;
int threat=0;
/*
----------------------------------------------------------
| |
| check to see if we have searched enough nodes that it |
| is time to peek at how much time has been used, or if |
| is time to check for operator keyboard input. this is |
| usually enough nodes to force a time/input check about |
| once per second, except when the target time per move |
| is very small, in which case we try to check the time |
| at least 10 times during the search. |
| |
----------------------------------------------------------
*/
tree->nodes_searched++;
if (--next_time_check <= 0) {
next_time_check=nodes_between_time_checks;
if (CheckInput()) Interrupt(ply);
time_abort+=TimeCheck(0);
if (time_abort) {
abort_search=1;
return(0);
}
}
if (ply >= MAXPLY-1) return(beta);
/*
----------------------------------------------------------
| |
| check for draw by repetition. |
| |
----------------------------------------------------------
*/
if (RepetitionCheck(tree,ply,wtm)) {
value=DrawScore(root_wtm==wtm);
if (value < beta) SavePV(tree,ply,value,0);
#if !defined(FAST)
if(ply <= trace_level) printf("draw by repetition detected, ply=%d.\n",ply);
#endif
return(value);
}
/*
----------------------------------------------------------
| |
| now call LookUp() to see if this position has been |
| searched before. if so, we may get a real score, |
| produce a cutoff, or get nothing more than a good move |
| to try first. there are four cases to handle: |
| |
| 1. LookUp() returned "EXACT_SCORE" if this score is |
| greater than beta, return beta. otherwise, return the |
| score. In either case, no further searching is needed |
| from this position. note that lookup verified that |
| the table position has sufficient "draft" to meet the |
| requirements of the current search depth remaining. |
| |
| 2. LookUp() returned "UPPER_BOUND" which means that |
| when this position was searched previously, every move |
| was "refuted" by one of its descendents. as a result, |
| when the search was completed, we returned alpha at |
| that point. we simply return alpha here as well. |
| |
| 3. LookUp() returned "LOWER_BOUND" which means that |
| when we encountered this position before, we searched |
| one branch (probably) which promptly refuted the move |
| at the previous ply. |
| |
| 4. LookUp() returned "AVOID_NULL_MOVE" which means |
| the hashed score/bound was no good, but it indicated |
| that trying a null-move in this position will be a |
| waste of time. |
| |
----------------------------------------------------------
*/
switch (LookUp(tree,ply,depth,wtm,&alpha,&beta,&threat)) {
case EXACT_SCORE:
if(alpha < beta) SavePV(tree,ply,alpha,1);
return(alpha);
case LOWER_BOUND:
return(beta);
case UPPER_BOUND:
return(alpha);
case AVOID_NULL_MOVE:
do_null=0;
}
/*
----------------------------------------------------------
| |
| now it's time to try a probe into the endgame table- |
| base files. this is done if (a) the previous move was |
| a capture or promotion, unless we are at very shallow |
| plies (<4) in the search; (b) there are less than 5 |
| pieces left (currently all interesting 4 piece endings |
| are available.) |
| |
----------------------------------------------------------
*/
if (EGTB_use) {
if (TotalPieces<=EGTB_use &&
(TotalPieces<5 || (WhiteRooks && BlackRooks))) do {
register int wpawn, bpawn;
int tb_value;
if (TotalWhitePawns && TotalBlackPawns) {
wpawn=FirstOne(WhitePawns);
bpawn=FirstOne(BlackPawns);
if (FileDistance(wpawn,bpawn) == 1) {
if(((Rank(wpawn)==RANK2) && (Rank(bpawn)>RANK3)) ||
((Rank(bpawn)==RANK7) && (Rank(wpawn)<RANK6)) ||
EnPassant(ply)) break;
}
}
tree->tb_probes++;
#if defined(SMP)
Lock(lock_io);
#endif
if (EGTBScore(tree, ply, wtm, &tb_value)) {
#if defined(SMP)
UnLock(lock_io);
#endif
tree->tb_probes_successful++;
alpha=tb_value;
if (abs(alpha) > MATE-100) alpha+=(alpha > 0) ? -(ply-1) : +(ply-1);
else if (alpha == 0) alpha=DrawScore(root_wtm==wtm);
if(alpha < beta) SavePV(tree,ply,alpha,2);
return(alpha);
}
#if defined(SMP)
UnLock(lock_io);
#endif
} while(0);
}
/*
----------------------------------------------------------
| |
| initialize. |
| |
----------------------------------------------------------
*/
tree->in_check[ply+1]=0;
tree->extended_reason[ply+1]=no_extension;
initial_alpha=alpha;
tree->last[ply]=tree->last[ply-1];
/*
----------------------------------------------------------
| |
| first, we try a null move to see if we can get a quick |
| cutoff with only a little work. this operates as |
| follows. instead of making a legal move, the side on |
| move 'passes' and does nothing. the resulting position |
| is searched to a shallower depth than normal (usually |
| one ply less but settable by the operator) this should |
| result in a cutoff or at least should set the lower |
| bound better since anything should be better than not |
| doing anything. |
| |
| this is skipped for any of the following reasons: |
| |
| 1. the side on move is in check. the null move |
| results in an illegal position. |
| 2. no more than one null move can appear in succession |
| or else the search will degenerate into nothing. |
| 3. the side on move has little material left making |
| zugzwang positions more